package com.xmb.common.service.wx.impl;

import com.github.binarywang.wxpay.bean.order.WxPayMpOrderResult;
import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest;
import com.github.binarywang.wxpay.config.WxPayConfig;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import com.github.binarywang.wxpay.service.impl.WxPayServiceImpl;
import com.xmb.common.constants.PayStatusEnum;
import com.xmb.common.dao.XmbWechatPaymentOrderMapper;
import com.xmb.common.entity.XmbWechatPaymentOrder;
import com.xmb.common.entity.XmbXcxAccountConfig;
import com.xmb.common.entity.structure.PayOrderInfo;
import com.xmb.common.exception.BusinessException;
import com.xmb.common.interceptor.CurrentContextUser;
import com.xmb.common.params.WxPayUnifiedOrdeParam;
import com.xmb.common.service.XcxAccountService;
import com.xmb.common.service.impl.GetPayOrderStrategy;
import com.xmb.common.service.impl.GetPayOrderStrategyHolder;
import com.xmb.common.service.wx.WxCommonService;
import com.xmb.common.service.wx.WxPayUnifiedOrderService;
import com.xmb.common.utils.NumberUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

/**
 * Created by lyndon on 2019/3/26.
 * 支付相关的service
 */
@Service
public class WxPayUnifiedOrderServiceImpl implements WxPayUnifiedOrderService {

    public final static String WX_TIME_PATTERN = "yyyyMMddHHmmss";

    public final static String PAYMENT_TYPE = "JSAPI";

    public final static String SPBILL_CREATE_IP = "192.168.0.1";

    /**
     * 支付后的回调接口
     */
    @Value("${wechat.pay.notify}")
    private String notifyUrl;

    @Resource
    private XmbWechatPaymentOrderMapper wechatPaymentOrderMapper;

    @Resource
    private XcxAccountService xcxAccountService;

    private WxPayService wxPayService;

    @Resource
    private WxCommonService wxCommonService;

    /**
     * 创建预付支付订单信息
     * @param payParam
     * @return
     * @throws WxPayException
     */
    @Transactional
    public WxPayMpOrderResult createWxPayOrder(WxPayUnifiedOrdeParam payParam) throws WxPayException {
        // 设置支付配置信息
        XmbXcxAccountConfig xcxAccountConfig = xcxAccountService.selectByAppid(CurrentContextUser.get().getAppid());
        if (xcxAccountConfig == null) {
            throw new BusinessException("无法获取当前小程序的支付配置信息");
        }
        this.setWxPayConfig(xcxAccountConfig);

        // 获取支付商品信息
        PayOrderInfo payProductInfo = this.getPayProductInfo(payParam);
        if (payProductInfo == null) {
            throw new BusinessException("无法获取到需要支付的商品信息");
        }


        // 获取支付商品信息
        XmbWechatPaymentOrder paymentOrder = new XmbWechatPaymentOrder();
        paymentOrder.setSenceId(payParam.getOrderId());
        paymentOrder.setSenceType(payParam.getOrderType());
        paymentOrder.setPayStatus(PayStatusEnum.paid.name());
        XmbWechatPaymentOrder wechatPaymentOrder = wechatPaymentOrderMapper.selectBySenceIdAndType(paymentOrder);
        if (wechatPaymentOrder != null) {
            throw new BusinessException("当前订单已完成支付成功");
        }

        // 构造预付单
        WxPayUnifiedOrderRequest orderRequest = new WxPayUnifiedOrderRequest();
        orderRequest.setBody(payProductInfo.getBody());
        orderRequest.setOutTradeNo(wxCommonService.getPayOutTranceNo(payProductInfo.getPayPrefix()));
        orderRequest.setTotalFee(NumberUtils.yuanToFee(payProductInfo.getOrderAmount().floatValue()));
        orderRequest.setSpbillCreateIp(SPBILL_CREATE_IP);
        LocalDateTime payTime = LocalDateTime.now();
        if (xcxAccountConfig.getIsSubAccount()) {
            orderRequest.setSubOpenid(CurrentContextUser.get().getOpenid());
        } else {
            orderRequest.setOpenid(CurrentContextUser.get().getOpenid());
        }
        orderRequest.setTimeStart(payTime.format(DateTimeFormatter.ofPattern(WX_TIME_PATTERN)));
        WxPayMpOrderResult wxPayMpOrderResult = wxPayService.createOrder(orderRequest);

        // 保存预付支付记录
        XmbWechatPaymentOrder xmbWechatPaymentOrder = new XmbWechatPaymentOrder();
        xmbWechatPaymentOrder.setPayStatus(PayStatusEnum.not_pay.name());
        xmbWechatPaymentOrder.setReceivableAmount(payProductInfo.getOrderAmount());
        xmbWechatPaymentOrder.setPaymentAmount(payProductInfo.getOrderAmount());
        xmbWechatPaymentOrder.setSenceType(payParam.getOrderType());
        xmbWechatPaymentOrder.setSenceId(payParam.getOrderId());
        xmbWechatPaymentOrder.setPayTime(LocalDateTime.now());
        xmbWechatPaymentOrder.setPaymemtType(PAYMENT_TYPE);
        xmbWechatPaymentOrder.setMerchantTransactionNo(orderRequest.getOutTradeNo());
        xmbWechatPaymentOrder.setUserId(CurrentContextUser.get().getUserId());
        xmbWechatPaymentOrder.setAppId(xcxAccountConfig.getSubAppid());
        xmbWechatPaymentOrder.setMerchantId(xcxAccountConfig.getSubMchId());
        this.saveWechatPaymentOrder(xmbWechatPaymentOrder);
        return wxPayMpOrderResult;
    }

    /**
     * 保存预付单信息
     * @param wechatPaymentOrder
     * @return
     */
    private int saveWechatPaymentOrder(XmbWechatPaymentOrder wechatPaymentOrder) {
        return wechatPaymentOrderMapper.insertSelective(wechatPaymentOrder);
    }


    /**
     * 设置支付配置信息
     */
    public void setWxPayConfig(XmbXcxAccountConfig xcxAccountConfig ){
        wxPayService = new WxPayServiceImpl();
        WxPayConfig payConfig = new WxPayConfig();
        payConfig.setAppId(xcxAccountConfig.getMainAppid());
        payConfig.setMchId(xcxAccountConfig.getMainMchId());
        payConfig.setMchKey(xcxAccountConfig.getMainMchKey());
        payConfig.setNotifyUrl(notifyUrl);
        payConfig.setTradeType(PAYMENT_TYPE);
        payConfig.setKeyPath(xcxAccountConfig.getKeyPath());
        if (xcxAccountConfig.getIsSubAccount()) {
            payConfig.setSubAppId(xcxAccountConfig.getSubAppid());
            payConfig.setSubMchId(xcxAccountConfig.getSubMchId());
        }
        wxPayService.setConfig(payConfig);
    }


    /**
     * 获取支付商品信息
     * @param payParam
     * @return
     */
    private PayOrderInfo getPayProductInfo(WxPayUnifiedOrdeParam payParam) {
        GetPayOrderStrategy strategy = GetPayOrderStrategyHolder.getSingleton().getStrategy(payParam.getOrderType());
        if (strategy != null) {
            return strategy.process(payParam);
        }
        return null;
    }
}
